import concurrent.futures
import threading
import requests
import sys
import os
import tempfile

class Downloader:
    """
    下载器
    """
    def __init__(self,url):
        self.url = url
        self.threadCount = 0
        self.update_progress_lock = threading.Lock()

    def __init__(self,url,thread_count):
        self.url = url
        self.thread_count = thread_count
        self.progress = 0
        self.file_size = 0
        self.update_progress_lock = threading.Lock()

    def __range_file(self):
        """
        按线程数拆分文件
        """
        self.range_result = []
        self.tmp_files = []
        range_avg = int(self.file_size / self.thread_count);
        for i in range(self.thread_count):
            self.tmp_files.append(tempfile.TemporaryFile())
            start_pos = i*range_avg
            end_pos = start_pos + range_avg
            if i > 0 :
                start_pos = start_pos + 1
            if i == self.thread_count -1:
                # 剩余的全部追加到最后一个线程下载区块中
                self.range_result.append([start_pos])
            else:
                self.range_result.append([start_pos, end_pos])

    def set_update_progress_handler(self, update_progress_handler):
        """
        设置进度更新执行器
        """
        self.update_progress_handler = update_progress_handler
        
    def __update_progress(self, data_size):
        """
        更新进度
        """
        #self.update_progress_lock.acquire()
        self.progress += data_size
        progress_rate = int(self.progress / self.file_size * 100)
        if self.update_progress_handler:
            self.update_progress_handler(progress_rate)
        #self.update_progress_lock.release()



    def __pre(self):
        """
        下载文件预处理
        """
        resp = requests.head(self.url, proxies=self.proxy)
        self.file_size = int(resp.headers['Content-Length'])
        self.if_range = resp.headers['ETag']
        self.__range_file()

    def __download(self,range_size, range_file):
        """
        执行下载操作
        """
        headers = {'if-range': self.if_range}
        if len(range_size) == 2:
            headers['Range'] = 'bytes={}-{}'.format(range_size[0],range_size[1])
        else:
            headers['Range'] = 'bytes={}-'.format(range_size[0])
        
        resp = requests.get(url=self.url, headers=headers, stream=True, proxies=self.proxy)
        for data in resp.iter_content(1024):
            print('线程:{};data length :{}'.format(threading.current_thread().getName(),len(data)))
            range_file.write(data)
            self.__update_progress(len(data))
        range_file.seek(0)

    def set_proxy(self, proxy):
        self.proxy = proxy

    def set_savefile(self,savefile):
        self.savefile = savefile

    def __merge_file(self):
        """
        合并文件
        """
        download_file = open(self.savefile,'ab')
        for tmp_file in self.tmp_files:
            download_file.write(tmp_file.read())
        download_file.close()

    def download(self):
        """
        下载文件
        """
        self.__pre()
        
        with concurrent.futures.ThreadPoolExecutor(max_workers=self.thread_count) as executor:
            for i in range(len(self.range_result)):
                executor.submit(self.__download,self.range_result[i],self.tmp_files[i])
        # 合并文件
        self.__merge_file()

if __name__ == "__main__":
    url = 'http://up.deskcity.org/pic_source/3c/10/47/3c1047bf1dd17e3cb6aeac429e06cea3.jpg'
    heads = {
        'Range': 'bytes=127-127'
    }
    resp = requests.head(url)
    print('file size',resp.headers['Content-Length'])
    print("xxxx",sys.argv)
    print("===================")
    downloader = Downloader(url, 4)
    downloader.download()
    
